<?php
defined('BASEPATH') OR exit('No direct script access allowed');
/**
 *  XJ_Loader Class
 *
 *  Loads framework components.
 *
 *  @package		XJPHP
 *  @subpackage	Libraries
 *  @category	Loader
 */

if ( ! class_exists('XJ_Loader'))
{
    class XJ_Loader{
        protected $_xj_model_paths		= array();
        protected $_xj_models			= array();
        protected $_xj_classes			= array();
        protected $_xj_base_classes     = array();
        protected $_xj_library_paths	= array();
        protected $_xj_loaded_files		= array();
        protected $_xj_helper_paths		= array();
        protected $_xj_varmap			= array('unit_test' => 'unit',
            'user_agent' => 'agent');
        public function __construct()
        {
            $this->_xj_model_paths = $_ENV['XJ_MODEL_DIR_PATH'];
            $this->_xj_library_paths = $_ENV['XJ_APP_DIR_PATH_ARR'];
        }
        public function view($view, $vars = array(), $return = FALSE)
        {
            return xj_load_view($view, $vars, $return);
        }
        public function model($model, $name = '', $db_conn = FALSE)
        {
            global $XJ;
            if (is_array($model))
            {
                foreach ($model as $babe)
                {
                    $this->model($babe);
                }
                return;
            }

            if ($model == '')
            {
                return;
            }
            $path = '';

            // Is the model in a sub-folder? If so, parse out the filename and path.
            if (($last_slash = strrpos($model, '/')) !== FALSE)
            {
                // The path is in front of the last slash
                $path = substr($model, 0, $last_slash + 1);

                // And the model name behind it
                $model = substr($model, $last_slash + 1);
            }

            if ($name == '')
            {
                $name = $model;
            }

            if (in_array($name, $this->_xj_models, TRUE))
            {
                return;
            }

            if (isset($XJ->$name))
            {
                xj_sys_show_error('The model name you are loading is the name of a resource that is already being used: '.$name);
            }

            $model = strtolower($model);
            $_path = '';
            foreach ($this->_xj_model_paths as $mod_path)
            {
                if ( ! file_exists($mod_path.'/'.$path.$model.'.php'))
                {
                    $_path = $_path.$mod_path.'/'.$path.$model.'.php   ';
                    continue;
                }

                if ($db_conn !== FALSE)
                {
                    if ($db_conn === TRUE)
                    {
                        $db_conn = '';
                    }

                    $this->database($db_conn, FALSE, TRUE);
                }

                if ( ! class_exists('XJ_Model'))
                {
                    //load_class('Model', 'core');
                }

                require_once($mod_path.'/'.$path.$model.'.php');

                $model = ucfirst($model);

                $XJ->$name = new $model();
                $XJ->$name->db = $XJ->db;
                $this->_xj_models[] = $name;
                return;
            }

            // couldn't find the model
            xj_sys_show_error('Unable to locate the model you have specified: '.$model.' _path='.$_path);
        }
        public function database($params = '', $return = FALSE, $active_record = NULL)
        {
            // Grab the super object
            global $XJ;

            // Do we even need to load the database class?
            if (class_exists('XJ_DB') AND $return == FALSE AND $active_record == NULL AND isset($XJ->db) AND is_object($XJ->db))
            {
                return FALSE;
            }

            require_once(BASEPATH.'xj_core/DB.php');

            if ($return === TRUE)
            {
                return DB($params, $active_record);
            }

            // Initialize the db variable.  Needed to prevent
            // reference errors with some configurations
            $XJ->db = FALSE;
            // Load the DB class
            $XJ->db =& DB($params, $active_record);

        }
        /**
         * Class Loader
         *
         * This function lets users load and instantiate classes.
         * It is designed to be called from a user's app controllers.
         *
         * @param	string	the name of the class
         * @param	mixed	the optional parameters
         * @param	string	an optional object name
         * @return	void
         */
        public function library($library = '', $params = NULL, $object_name = NULL)
        {
            if (is_array($library))
            {
                foreach ($library as $class)
                {
                    $this->library($class, $params);
                }

                return;
            }

            if ($library == '' OR isset($this->_xj_base_classes[$library]))
            {
                return FALSE;
            }

            if ( ! is_null($params) && ! is_array($params))
            {
                $params = NULL;
            }

            $this->_xj_load_class($library, $params, $object_name);
        }
        /**
         * Load class
         *
         * This function loads the requested class.
         *
         * @param	string	the item that is being loaded
         * @param	mixed	any additional parameters
         * @param	string	an optional object name
         * @return	void
         */
        protected function _xj_load_class($class, $params = NULL, $object_name = NULL)
        {
            global $XJ;
            // Get the class name, and while we're at it trim any slashes.
            // The directory path can be included as part of the class name,
            // but we don't want a leading slash
            $class = str_replace('.php', '', trim($class, '/'));

            // Was the path included with the class name?
            // We look for a slash to determine this
            $subdir = '';
            if (($last_slash = strrpos($class, '/')) !== FALSE)
            {
                // Extract the path
                $subdir = substr($class, 0, $last_slash + 1);

                // Get the filename from the path
                $class = substr($class, $last_slash + 1);
            }

            // We'll test for both lowercase and capitalized versions of the file name
            foreach (array(ucfirst($class), strtolower($class)) as $class)
            {
                // Lets search for the requested library file and load it.
                $is_duplicate = FALSE;
                foreach ($this->_xj_library_paths as $path)
                {
                    $filepath = $path.'libraries/'.$subdir.$class.'.php';

                    // Does the file exist?  No?  Bummer...
                    if ( ! file_exists($filepath))
                    {
                        continue;
                    }

                    // Safety:  Was the class already loaded by a previous call?
                    if (in_array($filepath, $this->_xj_loaded_files))
                    {
                        // Before we deem this to be a duplicate request, let's see
                        // if a custom object name is being supplied.  If so, we'll
                        // return a new instance of the object
                        if ( ! is_null($object_name))
                        {
                            if ( ! isset($XJ->$object_name))
                            {
                                return $this->_xj_init_class($class, '', $params, $object_name);
                            }
                        }
                        $is_duplicate = TRUE;
                        xj_log_message('debug', $class." class already loaded. Second attempt ignored.");
                        return;
                    }

                    include_once($filepath);
                    $this->_xj_loaded_files[] = $filepath;
                    return $this->_xj_init_class($class, '', $params, $object_name);
                }

            } // END FOREACH

            // One last attempt.  Maybe the library is in a subdirectory, but it wasn't specified?
            if ($subdir == '')
            {
                $path = strtolower($class).'/'.$class;
                return $this->_xj_load_class($path, $params);
            }

            // If we got this far we were unable to find the requested class.
            // We do not issue errors if the load call failed due to a duplicate request
            if ($is_duplicate == FALSE)
            {
                xj_log_message('error', "Unable to load the requested class: ".$class);
                xj_sys_show_error("Unable to load the requested class: ".$class);
            }
        }
        /**
         * Instantiates a class
         *
         * @param	string
         * @param	string
         * @param	bool
         * @param	string	an optional object name
         * @return	null
         */
        protected function _xj_init_class($class, $prefix = '', $config = FALSE, $object_name = NULL){
            global $XJ;
            $name = $prefix.$class;
            // Is the class name valid?
            if ( ! class_exists($name))
            {
                xj_log_message('error', "Non-existent class: ".$name);
                xj_sys_show_error("Non-existent class: ".$class);
            }
            // Set the variable name we will assign the class to
            // Was a custom class name supplied?  If so we'll use it
            $class = strtolower($class);
            if (is_null($object_name))
            {
                $classvar = ( ! isset($this->_xj_varmap[$class])) ? $class : $this->_xj_varmap[$class];
            }
            else
            {
                $classvar = $object_name;
            }
            //xj_sys_show_error("debug: ".json_encode($classvar));
            // Save the class name and object name
            $this->_xj_classes[$class] = $classvar;

            // Instantiate the class
            if ($config !== NULL)
            {
                $XJ->$classvar = new $name($config);
            }
            else
            {
                $XJ->$classvar = new $name;
            }
        }
    };
}


